<script lang="ts" setup>
import type { LowcodeGroovyApi } from '#/api/lowcode/groovy';

import { ref, watch } from 'vue';

import { Icon } from '@iconify/vue';
import { message } from 'ant-design-vue';

import { executeGroovyCode } from '#/api/lowcode/groovy';

interface Props {
  data?: LowcodeGroovyApi.GroovyScript;
}

const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits(['success']);

const scriptData = ref<LowcodeGroovyApi.GroovyScript>();
const running = ref(false);
const executeResult = ref<any>();
const parameters = ref('{}');

// 从脚本中提取参数
function extractParametersFromScript(scriptContent: string): Record<string, any> {
  if (!scriptContent) return {};
  
  const extractedParams: Record<string, any> = {};
  
  try {
    // 1. 匹配注释中的参数说明 // @param paramName type description
    const commentPattern = /\/\/\s*@param\s+(\w+)\s+(\w+)(?:\s+(.+))?/g;
    let commentMatch;
    while ((commentMatch = commentPattern.exec(scriptContent)) !== null) {
      const [, paramName, type, description] = commentMatch;
      if (paramName) {
        extractedParams[paramName] = inferParameterValueByType(type, description);
      }
    }
    
    // 2. 匹配各种 params 访问模式
    const paramPatterns = [
      /params\.(\w+)/g,                    // params.xxx
      /params\['([^']+)'\]/g,              // params['xxx']
      /params\["([^"]+)"\]/g,              // params["xxx"]
      /params\.get\(['"]([^'"]+)['"]\)/g,  // params.get('xxx')
      /binding\.params\.(\w+)/g,           // binding.params.xxx
    ];
    
    paramPatterns.forEach(pattern => {
      let match;
      while ((match = pattern.exec(scriptContent)) !== null) {
        const paramName = match[1];
        if (paramName && !extractedParams[paramName]) {
          // 如果注释中没有定义，根据参数名推断类型和默认值
          extractedParams[paramName] = inferParameterValue(paramName);
        }
      }
    });
    
    // 3. 匹配变量赋值模式 def xxx = params.yyy
    const assignmentPattern = /def\s+(\w+)\s*=\s*params\.(\w+)/g;
    let assignMatch;
    while ((assignMatch = assignmentPattern.exec(scriptContent)) !== null) {
      const [, varName, paramName] = assignMatch;
      if (paramName && !extractedParams[paramName]) {
        extractedParams[paramName] = inferParameterValue(paramName);
      }
    }
    
    // 4. 检查是否有通用的params使用但没有具体参数
    // 如果脚本使用了params但没有具体参数访问，提供默认参数
    const hasParamsUsage = /\bparams\b/.test(scriptContent) && !/params\.\w+/.test(scriptContent);
    
    // 5. 对于简单脚本，分析可能的变量引用
    // 如果脚本很简单，且没有找到明确的params访问，尝试推断变量
    if ((Object.keys(extractedParams).length === 0 && scriptContent.length < 200) || hasParamsUsage) {
      // 匹配可能的变量使用，排除常见关键字
      const excludeWords = [
        'return', 'def', 'if', 'else', 'for', 'while', 'class', 'import', 
        'true', 'false', 'null', 'new', 'this', 'super', 'static', 'final',
        'println', 'print', 'binding', 'params', 'String', 'Integer', 'Date'
      ];
      
      const variablePattern = /\b([a-zA-Z_]\w*)\b/g;
      const usedVariables = new Set<string>();
      let varMatch;
      
      while ((varMatch = variablePattern.exec(scriptContent)) !== null) {
        const variable = varMatch[1];
        if (!excludeWords.includes(variable) && 
            !variable.match(/^[A-Z]/) && // 排除可能的类名
            variable.length > 1) {
          usedVariables.add(variable);
        }
      }
      
      // 将找到的变量作为潜在参数
      usedVariables.forEach(variable => {
        extractedParams[variable] = inferParameterValue(variable);
      });
      
      // 如果是通用params使用但没找到具体变量，提供默认参数示例
      if (hasParamsUsage && Object.keys(extractedParams).length === 0) {
        extractedParams['name'] = 'example_name';
        extractedParams['id'] = 1;
        extractedParams['data'] = 'example_data';
      }
    }
    
  } catch (error) {
    console.warn('参数提取失败:', error);
  }
  
  return extractedParams;
}

// 根据参数名推断参数值
function inferParameterValue(paramName: string): any {
  const lowerName = paramName.toLowerCase();
  
  // 数字类型
  if (lowerName.includes('id') || lowerName.includes('count') || 
      lowerName.includes('size') || lowerName.includes('num')) {
    return 1;
  }
  
  // 布尔类型
  if (lowerName.includes('enable') || lowerName.includes('active') || 
      lowerName.includes('flag') || lowerName.includes('debug')) {
    return true;
  }
  
  // 数组类型
  if (lowerName.includes('list') || lowerName.includes('items') || 
      lowerName.includes('array')) {
    return [];
  }
  
  // 对象类型
  if (lowerName.includes('config') || lowerName.includes('option') || 
      lowerName.includes('setting')) {
    return {};
  }
  
  // 默认字符串
  return `${paramName}_example`;
}

// 根据类型推断参数值
function inferParameterValueByType(type: string, description?: string): any {
  const lowerType = type.toLowerCase();
  
  switch (lowerType) {
    case 'string':
    case 'str':
      return description ? `${description}_example` : 'example_value';
    case 'int':
    case 'integer':
    case 'number':
      return 1;
    case 'boolean':
    case 'bool':
      return true;
    case 'array':
    case 'list':
      return [];
    case 'object':
    case 'map':
      return {};
    default:
      return 'example_value';
  }
}

// 生成参数示例
function generateParameterExample(extractedParams: Record<string, any>): string {
  if (Object.keys(extractedParams).length === 0) {
    return '{}';
  }
  
  return JSON.stringify(extractedParams, null, 2);
}

// 监听props.data变化
watch(() => props.data, (newData) => {
  if (newData) {
    scriptData.value = newData;
    executeResult.value = undefined;
    
    // 自动提取参数
    if (newData.scriptContent) {
      const extractedParams = extractParametersFromScript(newData.scriptContent);
      const parameterExample = generateParameterExample(extractedParams);
      parameters.value = parameterExample;
    } else {
      parameters.value = '{}';
    }
  }
}, { immediate: true });

// 执行脚本
async function handleExecute() {
  if (!scriptData.value?.scriptContent?.trim()) {
    message.error('脚本内容不能为空');
    return;
  }

  try {
    running.value = true;
    executeResult.value = undefined;

    let params = {};
    if (parameters.value.trim()) {
      // 验证JSON格式
      try {
        params = JSON.parse(parameters.value);
      } catch (error) {
        message.error('参数格式错误，请输入有效的JSON格式');
        return;
      }
      
      // 验证参数安全性
      const jsonStr = JSON.stringify(params);
      if (jsonStr.length > 5000) {
        message.error('参数内容过长，请控制在合理范围内');
        return;
      }
      
      // 检查是否包含危险内容
      const dangerousKeys = ['__proto__', 'constructor', 'prototype'];
      const hasDangerousKeys = (obj: any): boolean => {
        if (typeof obj !== 'object' || obj === null) return false;
        return Object.keys(obj).some(key => 
          dangerousKeys.includes(key) || 
          (typeof obj[key] === 'object' && hasDangerousKeys(obj[key]))
        );
      };
      
      if (hasDangerousKeys(params)) {
        message.error('参数包含不安全内容');
        return;
      }
    }

    const result = await executeGroovyCode(scriptData.value.scriptContent, params);
    
    // 检查响应结构
    let executeData = result;
    if (result && typeof result === 'object' && 'data' in result) {
      executeData = result.data;
    }
    
    executeResult.value = executeData;
    message.success('脚本执行完成');
    emit('success');
  } catch (error: any) {
    
    let errorMessage = '脚本执行失败';
    let errorDetails = '';
    
    if (error?.response?.data) {
      const responseData = error.response.data;
      if (responseData.message) {
        errorMessage = responseData.message;
      }
      if (responseData.error) {
        errorDetails = responseData.error;
      }
    } else if (error?.message) {
      errorMessage = error.message;
    }
    
    executeResult.value = {
      success: false,
      error: errorDetails || errorMessage,
      message: errorMessage,
    };
    
    message.error(errorMessage);
  } finally {
    running.value = false;
  }
}
</script>

<template>
  <div>
    <a-space direction="vertical" style="width: 100%" size="large">
      <!-- 脚本信息 -->
      <a-descriptions title="脚本信息" :column="2" size="small">
        <a-descriptions-item label="脚本名称">
          {{ scriptData?.scriptName }}
        </a-descriptions-item>
        <a-descriptions-item label="显示名称">
          {{ scriptData?.displayName }}
        </a-descriptions-item>
        <a-descriptions-item label="脚本描述" :span="2">
          {{ scriptData?.description || '暂无描述' }}
        </a-descriptions-item>
      </a-descriptions>

      <!-- 脚本内容预览 -->
      <a-card title="脚本内容预览" size="small">
        <pre style="background: #f8f8f8; padding: 12px; border-radius: 4px; max-height: 150px; overflow-y: auto; font-family: monospace; font-size: 12px;">{{ 
          scriptData?.scriptContent?.substring(0, 300) + (scriptData?.scriptContent && scriptData.scriptContent.length > 300 ? '...' : '') 
        }}</pre>
      </a-card>

      <!-- 执行参数 -->
      <a-card title="📝 执行参数" size="small">
        <template #extra>
          <a-tag color="blue">自动生成</a-tag>
        </template>
        <a-textarea
          v-model:value="parameters"
          placeholder='{"name": "张三", "age": 30, "items": ["apple", "banana"]}'
          :rows="4"
          :style="{ fontFamily: 'monospace', fontSize: '14px' }"
        />
        <div style="margin-top: 8px; color: #666; font-size: 12px;">
          <strong>示例:</strong> {"userId": 123, "debug": true, "config": {"timeout": 5000}}
        </div>
        <div style="margin-top: 4px; color: #999; font-size: 11px;">
          如果不需要参数，请保持默认的空对象 {}
        </div>
      </a-card>

      <!-- 执行按钮 -->
      <div style="text-align: center;">
        <a-button
          type="primary"
          size="large"
          :loading="running"
          @click="handleExecute"
        >
          <template #icon>
            <Icon icon="ant-design:play-circle-outlined" />
          </template>
          执行脚本
        </a-button>
      </div>

      <!-- 执行结果 -->
      <a-card
        v-if="executeResult"
        title="执行结果"
        size="small"
      >
        <a-alert
          :type="executeResult.success !== false ? 'success' : 'error'"
          show-icon
          style="margin-bottom: 12px"
        >
          <template #message>
            {{ executeResult.success !== false ? '脚本执行成功' : '脚本执行失败' }}
          </template>
        </a-alert>

        <pre style="background: #f5f5f5; padding: 12px; border-radius: 4px; white-space: pre-wrap; font-family: monospace; max-height: 300px; overflow-y: auto;">{{ 
          executeResult.error ? executeResult.error : JSON.stringify(executeResult, null, 2) 
        }}</pre>
      </a-card>
    </a-space>
  </div>
</template>